package Model;


import java.nio.ByteBuffer;
import java.security.SecureRandom;

import bl.*;


public class TokenManager 
{
	enum eFlags
	{
		SimplePush((byte)1),
		SimplePull((byte)2),
		PushWithProof((byte)3),
		PullWithProof((byte)4);
		
		private final byte m_byte;
		
		private eFlags(byte i) 
		{			
			m_byte = i;
		}
		
		public byte getByte()
		{
			return m_byte;
		}
	}
	
	PublicParametersI m_ppClient;
	TokenClassesManagerI m_manager; 
	VEBTokensGeneratorI m_ClientSideTokenGenerator;
	FriendClientDataI m_clientDetails; 
	int m_epoch;
	static SecureRandom sr = new SecureRandom();
	byte[] m_clientPullTokenBytes;
	byte[] m_clientProofBytes;
	
	public TokenManager()
	{
		m_epoch = sr.nextInt(18376498);
		// via the this interface you create instances of the relevant methods.
		m_manager = new IntegersTokenClassesManager();
	}
	
	public void setPublicParameters(byte[] ppBytes) throws Exception
	{
		/*// verify the length of the public parameters bytes representation
		if (ppBytes.length != ppPO.GetPublicParametersLengthBytes())
			throw new Exception("The byte[] representation of the public parameters is different from the data in the public information");*/
		
		m_ppClient = m_manager.CreatePublicParameters(ppBytes);
		generateMyKies();
	}
	
	public void generateMyKies() throws IneligibleTypeException
	{
		// The client knows the public parameters and also his own secret key and the details of its friends.
		// In this example, the client knows the "public" part of the identity (like in the simple scenario).
		m_ClientSideTokenGenerator = m_manager.CreateVEBTokenGenerator(m_ppClient);
		
		// Generate Secret Key (for the PRF, and possibly for messages encryption), and create identity for the client (both secret and "public" parameters)
		m_clientDetails = m_manager.GenerateNewClient(m_ppClient);
		
		// first create the token
		VEBTokenI clientPullToken = m_ClientSideTokenGenerator.CreateToken(m_epoch, m_clientDetails);
		m_clientPullTokenBytes = clientPullToken.getBytes(m_ppClient);
		
		// then create the proof
		NIZKproofI clientProof = m_ClientSideTokenGenerator.CreateProof(clientPullToken, m_clientDetails.getClientData());
		m_clientProofBytes = clientProof.GetBytes();
	}
	
	
	public byte[] getMyToken()
	{
		return m_clientPullTokenBytes;		
	}
	
	public String getMyTokenString()
	{
		StringBuilder sb=new StringBuilder();
	    for(byte s: m_clientPullTokenBytes)
	        sb.append(s + " ");
	    return sb.toString();				
	}
	
	public byte[] getPullDummyToken()
	{
		return m_clientPullTokenBytes;		
	}
	
	public byte[] getPushDummyToken()
	{
		return m_clientPullTokenBytes;		
	}
	
	public byte[] getProof()
	{
		return m_clientProofBytes;		
	}
	
	public byte[] getPushWithProofMessage(String message, byte[] token)
	{
		byte[] bMessage = message.getBytes();		
		
		return arraysConcatenation(eFlags.PushWithProof.getByte(), bMessage, token);
	}
	
	public byte[] getPushMessage(byte[] message, byte[] token)
	{		
		return arraysConcatenation(token, message);
	}
	
	public byte[] getPullMessage(byte[] token)
	{			
		return arraysConcatenation(eFlags.SimplePull.getByte(), token);
	}
	
	public byte[] getPullMessage(byte[] bs, byte[] bs2, Integer index)
	{			
		return arraysConcatenation(new byte[]{eFlags.PullWithProof.getByte()}, bs, ByteBuffer.allocate(4).putInt(index).array(), bs2);
	}
	
	public byte[] getSimplePushSimplePull(byte[] message, byte[] token)
	{
		return arraysConcatenation(getPushMessage(message, token), getPullMessage(getMyToken()));
	}
	
	public byte[] arraysConcatenation(Object... arrays)
	{
		int size = 0;
		for (int i = 0; i < arrays.length; i++) 
		{
			size += ((byte[])arrays[i]).length;
		}
		
		byte[] array = new byte[size];
		
		int counter = 0;
		for (int i = 0; i < arrays.length; i++) 
		{
			System.arraycopy(arrays[i], 0, array, counter, ((byte[])arrays[i]).length);
			counter += ((byte[])arrays[i]).length;
		}		
		
		return array;
	}

	public byte[] getPubliParamsMessage() 
	{
		byte[] b = new byte[1];
		b[0] = 0;
		
		return 	b;	
	}

	public byte[] getPushAndPullMessage(byte[] token, byte[] proof, int index) {
		// TODO Auto-generated method stub
		return null;
	}
}
